﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

using Skyhook.Core.Input;

namespace Skyhook.Core.Screens
{
    public enum ScreenState
    {
        TransitionOn,
        Active,
        TransitionOff,
        Hidden
    }

    public class GameScreen : ApplicationComponent
    {
        public bool IsPopup {get; protected set;}
        
        protected TimeSpan TransitionOnTime = TimeSpan.Zero;
        protected TimeSpan TransitionOffTime = TimeSpan.Zero;
        
        protected float TransitionPosition = 0;
        
        public ScreenState ScreenState {get; internal set;}

        public bool IsExiting { get; internal set; }
        public bool IsVisible
        {
            get
            {
                return (ScreenState == ScreenState.TransitionOn ||
                        ScreenState == ScreenState.Active ||
                        ScreenState == ScreenState.TransitionOff);
            }
        }

        public GameScreenManager ScreenManager {get; private set;}

        public GameScreen(GameScreenManager screenmanager)
        {
            ScreenManager = screenmanager;
            Owner = screenmanager;
            Root = screenmanager.Root;
            Data = screenmanager.Data;

            ScreenState = ScreenState.Hidden;
        }

        internal override void UpdateWithComponents(GameTime time)
        {
            switch (ScreenState)
            {
                case ScreenState.TransitionOff:
                    if (!UpdateTransition(time, TransitionOffTime, -1))
                    {
                        ScreenState = ScreenState.Hidden;
                    }
                    break;
                case ScreenState.TransitionOn:
                    if (!UpdateTransition(time, TransitionOnTime, 1))
                    {
                        ScreenState = ScreenState.Active;
                    }
                    break;
            }

            base.UpdateWithComponents(time);
        }

        bool UpdateTransition(GameTime gametime, TimeSpan time, int direction)
        {
            float transitiondelta;

            if (time == TimeSpan.Zero)
            {
                transitiondelta = 1;
            }
            else
            {
                transitiondelta = (float)(gametime.ElapsedGameTime.TotalMilliseconds /
                                          time.TotalMilliseconds);
            }

            TransitionPosition += transitiondelta * direction;

            if (((direction < 0) && (TransitionPosition <= 0)) ||
                ((direction > 0) && (TransitionPosition >= 1)))
            {
                TransitionPosition = MathHelper.Clamp(TransitionPosition, 0, 1);
                return false;
            }

            return true;
        }

        public void Hide()
        {
            if (TransitionOffTime == TimeSpan.Zero)
            {
                ScreenState = ScreenState.Hidden;
            }
            else if (ScreenState == ScreenState.TransitionOn ||
                ScreenState == ScreenState.Active)
            {
                ScreenState = ScreenState.TransitionOff;
                TransitionPosition = 1;
            }
        }

        public void Show()
        {
            if (ScreenState == ScreenState.TransitionOff ||
                ScreenState == ScreenState.Hidden)
            {
                ScreenManager.AddScreen(this);
            }
            else
            {
                return;
            }
            Activate();
        }

        internal void Activate()
        {
            if (TransitionOnTime == TimeSpan.Zero)
            {
                ScreenState = ScreenState.Active;
            }
            else
            {
                ScreenState = ScreenState.TransitionOn;
                TransitionPosition = 0;
            }
        }

        protected virtual void OnKeyDown(Keys key)
        {
        }
        protected virtual void OnKeyPressed(Keys key)
        {
        }

        protected virtual void OnMouseMove(int x, int y)
        {
        }

        protected virtual void OnMouseLeftDown(int x, int y)
        {
        }
        protected virtual void OnMouseLeftClick(int x, int y)
        {
        }

        protected virtual void OnMouseRightDown(int x, int y)
        {
        }
        protected virtual void OnMouseRightClick(int x, int y)
        {
        }

        public void ConnectInputAndSaveStatus()
        {
            ConnectInput();
            HasInput = true;
        }

        public void DisconnectInputAndSaveStatus()
        {
            DisconnectInput();
            HasInput = false;
        }

        public virtual bool HasInput { get; private set; }

        protected virtual void ConnectInput()
        {
            InputEvents.KeyPressed += OnKeyPressed;
            InputEvents.KeyDown += OnKeyDown;
            InputEvents.MouseLeftDown += OnMouseLeftDown;
            InputEvents.MouseLeftClick += OnMouseLeftClick;
            InputEvents.MouseRightClick += OnMouseRightClick;
            InputEvents.MouseRightDown += OnMouseRightDown;
            InputEvents.MouseMove += OnMouseMove;
        }

        protected virtual void DisconnectInput()
        {
            InputEvents.KeyPressed -= OnKeyPressed;
            InputEvents.KeyDown -= OnKeyDown;
            InputEvents.MouseLeftDown -= OnMouseLeftDown;
            InputEvents.MouseLeftClick -= OnMouseLeftClick;
            InputEvents.MouseRightClick -= OnMouseRightClick;
            InputEvents.MouseRightDown -= OnMouseRightDown;
            InputEvents.MouseMove -= OnMouseMove;
        }
    }
}
